/*
The MIT License
Copyright (c) 2019 Lehrstuhl Informatik 11 - RWTH Aachen University
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE

This file is part of embeddedRTPS.

Author: i11 - Embedded Software, RWTH Aachen University
*/

#include "rtps/rtps.h"
#include "lwip/sys.h"
#include <time.h>


//config.h
const VendorId_t VENDOR_ID = {{13, 37}};
const uint8_t IP_ADDRESS[4] = {192, 168, 1, 2}; // Needs to be set in lwipc
const GuidPrefix_t BASE_GUID_PREFIX = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9}};
const Duration_t SPDP_DEFAULT_REMOTE_LEASE_DURATION = {100, 0}; // Default lease duration for remo
const Duration_t SPDP_MAX_REMOTE_LEASE_DURATION = {180, 0}; // Absolute maximum lease duration, ign

int OVERALL_HEAP_SIZE =
    THREAD_POOL_NUM_WRITERS * THREAD_POOL_WRITER_STACKSIZE +
    THREAD_POOL_NUM_READERS * THREAD_POOL_READER_STACKSIZE +
    MAX_NUM_PARTICIPANTS * SPDP_WRITER_STACKSIZE +
    NUM_STATEFUL_WRITERS * HEARTBEAT_STACKSIZE;

//types.h
/* Default Values */
/* Default Values */
const EntityId_t ENTITYID_UNKNOWN = {{0}, USER_DEFINED_UNKNOWN};
const EntityId_t ENTITYID_BUILD_IN_PARTICIPANT = {
    {00, 00, 01}, BUILD_IN_PARTICIPANT};
const EntityId_t ENTITYID_SEDP_BUILTIN_TOPIC_WRITER = {
    {00, 00, 02}, BUILD_IN_WRITER_WITH_KEY};
const EntityId_t ENTITYID_SEDP_BUILTIN_TOPIC_READER = {
    {00, 00, 02}, BUILD_IN_READER_WITH_KEY};
const EntityId_t ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER = {
    {00, 00, 03}, BUILD_IN_WRITER_WITH_KEY};
const EntityId_t ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER = {
    {00, 00, 03}, BUILD_IN_READER_WITH_KEY};
const EntityId_t ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER = {
    {00, 00, 04}, BUILD_IN_WRITER_WITH_KEY};
const EntityId_t ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER = {
    {00, 00, 04}, BUILD_IN_READER_WITH_KEY};
const EntityId_t ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER = {
    {00, 01, 00}, BUILD_IN_WRITER_WITH_KEY};
const EntityId_t ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER = {
    {00, 01, 00}, BUILD_IN_READER_WITH_KEY};
const EntityId_t ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER = {
    {00, 02, 00}, BUILD_IN_WRITER_WITH_KEY};
const EntityId_t ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER = {
    {00, 02, 00}, BUILD_IN_READER_WITH_KEY};

const GuidPrefix_t GUIDPREFIX_UNKNOWN = {0};
const Guid_t GUID_UNKNOWN = {{{0}}, {{0}, USER_DEFINED_UNKNOWN}};

const ParticipantId_t PARTICIPANT_ID_INVALID = -1;

const ProtocolVersion_t PROTOCOLVERSION_1_0 = {1, 0};
const ProtocolVersion_t PROTOCOLVERSION_1_1 = {1, 1};
const ProtocolVersion_t PROTOCOLVERSION_2_0 = {2, 0};
const ProtocolVersion_t PROTOCOLVERSION_2_1 = {2, 1};
const ProtocolVersion_t PROTOCOLVERSION_2_2 = {2, 2};
const ProtocolVersion_t PROTOCOLVERSION = PROTOCOLVERSION_2_2;

const SequenceNumber_t SEQUENCENUMBER_UNKNOWN = {-1, 0};

const Time_t TIME_ZERO = {0, 0};
const Time_t TIME_INVALID = {-1, 0xFFFFFFFF};
const Time_t TIME_INFINITE = {0x7FFFFFFF, 0xFFFFFFFF};

const VendorId_t VENDOR_UNKNOWN = {0};

// Currently initialization is expected to be done in project main for e.g.
// Aurix and STM32
#if defined(unix) || defined(__unix__) || defined(WIN32) || defined(_WIN32) || \
    defined(__WIN32) && !defined(__CYGWIN__)

#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwipcfg.h"
#include <lwip/tcpip.h>

#if defined(unix) || defined(__unix__)
#include "netif/tapif.h"
#elif defined(WIN32) || defined(_WIN32) ||                                     \
    defined(__WIN32) && !defined(__CYGWIN__)
#include "../pcapif.h"
#include "default_netif.h"
#else
#include "ethernetif.h"
#endif

#define INIT_VERBOSE 0

static struct netif netif;

static void init(void *arg) {
  if (arg == NULL) {
#if INIT_VERBOSE
    printf("Failed to init. NULL passed");
#endif
    return;
  }
  sys_sem_t *init_sem = (sys_sem_t *)(arg);

  srand((unsigned int)time(NULL));

  ip4_addr_t ipaddr;
  ip4_addr_t netmask;
  ip4_addr_t gw;
  LWIP_PORT_INIT_GW(&gw);
  LWIP_PORT_INIT_IPADDR(&ipaddr);
  LWIP_PORT_INIT_NETMASK(&netmask);
#if INIT_VERBOSE
  printf("Starting lwIP, local interface IP is %s\n", ip4addr_ntoa(&ipaddr));
#endif

#if defined(unix) || defined(__unix__)
  netif_add(&netif, &ipaddr, &netmask, &gw, NULL, tapif_init, tcpip_input);
#elif defined(WIN32) || defined(_WIN32) ||                                     \
    defined(__WIN32) && !defined(__CYGWIN__)
  netif_add(&netif, &ipaddr, &netmask, &gw, NULL, pcapif_init, tcpip_input);
#else
  netif_add(&netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init,
            tcpip_input);
#endif

  netif_set_default(&netif);
  netif_set_up(netif_default);

  sys_sem_signal(init_sem);
}

void LwIPInit() {
  /* no stdio-buffering, please! */
  setvbuf(stdout, NULL, _IONBF, 0);

  err_t err;
  sys_sem_t init_sem;

  err = sys_sem_new(&init_sem, 0);
  LWIP_ASSERT("failed to create init_sem", err == ERR_OK);
  LWIP_UNUSED_ARG(err);
  tcpip_init(init, &init_sem);
  /* we have to wait for initialization to finish before
   * calling update_adapter()! */
  sys_sem_wait(&init_sem);
  sys_sem_free(&init_sem);
}

void rtps_init() {
  // TODO This is not threadsafe. Might cause problems in tests. For now, it
  // seems to work.
  static bool initialized = false;
  if (!initialized) {
    LwIPInit();
    initialized = true;
  }
}
#endif

#undef INIT_VERBOSE
